package com.yoyo.yyadsdk.util;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;

import com.downloader.Progress;
import com.google.gson.Gson;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import static com.yoyo.yyadsdk.util.ApiConstants.GET;
import static com.yoyo.yyadsdk.util.ApiConstants.UTF_8;


/**
 * Created by xiaoyehai on 2018/5/21 0021.
 */

public class HttpUtils {

    //线程池
    private static ExecutorService executor;
    private static Handler mHandler;

    static {
        executor = Executors.newFixedThreadPool(5);
        mHandler = new Handler();
    }

    /**
     * 执行网络请求操作,返回数据会解析成字符串String
     *
     * @param method 请求方式(需要传入String类型的参数:"GET","POST")
     * @param url    请求的url
     * @param params 请求的参数
     */
    public static String doHttpRequest(final String method, final String url,
                                       final Map<String, String> params, final StringCallback callback) {

        executor.execute(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                OutputStream outputStream = null;
                try {
                    connection = getConnection(url, method);

                    // 只有当POST请求时才会执行此代码段
                    if (params != null) {
                        outputStream = getOutputStream(connection, params);
                    }

                    int responseCode = connection.getResponseCode();
                    if (responseCode == 200) {
                        InputStream inputStream = connection.getInputStream();
                        String result = inputStream2String(inputStream);
                        if (result != null && callback != null) {
                            postSuccessString(callback, result);
                        }
                    } else {
                        if (callback != null) {
                            postFailed(callback, responseCode, new Exception("请求数据失败：" + responseCode));
                        }
                    }

                } catch (final Exception e) {
                    e.printStackTrace();
                    if (callback != null) {
                        postFailed(callback, 0, e);
                    }

                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        return null;
    }

    /**
     * 执行网络请求操作,返回数据是Bitmap
     *
     * @param method 请求方式(需要传入String类型的参数:"GET","POST")
     * @param url    请求的url
     * @param params 请求的参数
     */
    public static String doHttpRequest(final String method, final String url,
                                       final Map<String, String> params, final BitmapCallback callback) {

        executor.execute(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                OutputStream outputStream = null;
                InputStream inputStream = null;
                try {
                    connection = getConnection(url, method);

                    // 只有当POST请求时才会执行此代码段
                    if (params != null) {
                        outputStream = getOutputStream(connection, params);
                    }

                    int responseCode = connection.getResponseCode();
                    if (responseCode == 200) {
                        inputStream = connection.getInputStream();
                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                        if (bitmap != null && callback != null) {
                            postSuccessBitmap(callback, bitmap);
                        }
                    } else {
                        if (callback != null) {
                            postFailed(callback, responseCode, new Exception("请求图片失败：" + responseCode));
                        }
                    }


                } catch (final Exception e) {
                    e.printStackTrace();
                    if (callback != null) {
                        postFailed(callback, 0, e);
                    }

                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        return null;
    }

    /**
     * 执行网络请求操作,返回数据是byte[]
     *
     * @param method 请求方式(需要传入String类型的参数:"GET","POST")
     * @param url    请求的url
     * @param params 请求的参数
     */
    public static String doHttpRequest(final String method, final String url,
                                       final Map<String, String> params, final ByteArrayCallback callback) {

        executor.execute(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                OutputStream outputStream = null;
                try {
                    connection = getConnection(url, method);

                    // 只有当POST请求时才会执行此代码段
                    if (params != null) {
                        outputStream = getOutputStream(connection, params);
                    }

                    int responseCode = connection.getResponseCode();
                    if (responseCode == 200) {
                        InputStream inputStream = connection.getInputStream();
                        byte[] bytes = inputStream2ByteArray(inputStream);
                        if (bytes != null && callback != null) {
                            postSuccessByte(callback, bytes);
                        }
                    } else {
                        if (callback != null) {
                            postFailed(callback, responseCode, new Exception("请求图片失败：" + responseCode));
                        }
                    }

                } catch (final Exception e) {
                    e.printStackTrace();
                    if (callback != null) {
                        postFailed(callback, 0, e);
                    }

                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        return null;
    }

    private static HttpURLConnection getConnection(String url, String method) throws IOException {
//                    URL u = new URL(url);
//                    connection = (HttpURLConnection) u.openConnection();
        HttpURLConnection connection = connect(url);
        // 设置输入可用
        connection.setDoInput(true);
        // 设置输出可用
        connection.setDoOutput(true);
        // 设置请求方式
        connection.setRequestMethod(method);
        // 设置连接超时
        connection.setConnectTimeout(5000);
        // 设置读取超时
        connection.setReadTimeout(5000);
        // 设置缓存不可用
        connection.setUseCaches(false);
        // 开始连接
        connection.connect();
        return connection;
    }

    /**
     * @param urlPath  下载路径
     * @param fileName 下载存放目录
     * @return 返回下载文件
     */
    public static void downloadFile(final String urlPath, final String filePath, final String fileName, final FileCallback fileCallback) {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                File file;
                HttpURLConnection connection = null;
                try {
//                    URL url = new URL(urlPath);
                    connection = connect(urlPath);
                    // 连接类的父类，抽象类
//                    URLConnection urlConnection = url.openConnection();
                    // http的连接类
//                    connection = (HttpURLConnection) urlConnection;
                    // 设定请求的方法，默认是 GET POST
                    connection.setRequestMethod(GET);
                    // 设置字符编码
                    connection.setRequestProperty("Charset", UTF_8);
//                    connection.setRequestProperty("Content-Type", "application/octet-stream");
                    connection.setDoOutput(false);
                    connection.setDoInput(true);
                    connection.setRequestProperty("Connection", "Keep-Alive");
                    // 打开到此 URL 引用的资源的通信链接（如果尚未建立这样的连接）。
                    connection.connect();

                    // 文件大小
                    int fileLength = connection.getContentLength();

                    // 文件名

                    System.out.println("file length---->" + fileLength);
                    int responseCode = connection.getResponseCode();
                    if (responseCode == 200) {
                        BufferedInputStream bin = new BufferedInputStream(connection.getInputStream());
                        file = new File(filePath, fileName);
                        if (!file.getParentFile().exists()) {
                            file.getParentFile().mkdirs();
                        }
                        if (file.exists()) {
                            file.delete();
                        }
                        OutputStream out = new FileOutputStream(file);
                        int size;
                        int len = 0;
                        byte[] buf = new byte[1024];
                        long currentTimeMillis = System.currentTimeMillis();
                        while ((size = bin.read(buf)) != -1) {
                            len += size;
                            out.write(buf, 0, size);
                            // 打印下载百分比
                            if (System.currentTimeMillis() - currentTimeMillis > 500) {
                                postProgressFile(fileCallback, new Progress(len, fileLength));
                            }
                        }
                        bin.close();
                        out.close();
                        postSuccessFile(fileCallback, file);
                    } else {
                        postFailed(fileCallback, responseCode, new Exception("请求数据失败：" + connection.getResponseMessage()));
                    }
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
            }
        });
    }


    /**
     * 执行网络请求操作,返回数据是对象
     *
     * @param method 请求方式(需要传入String类型的参数:"GET","POST")
     * @param url    请求的url
     * @param params 请求的参数
     */
    public static <T> void doHttpRequest(final String method, final String url,
                                         final Map<String, String> params, final Class<T> cls, final ObjectCallback<T> callback) {

        executor.execute(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                OutputStream outputStream = null;
                try {
                    connection = getConnection(url, method);
                    // 只有当POST请求时才会执行此代码段
                    if (params != null) {
                        outputStream = getOutputStream(connection, params);
                    }
                    int responseCode = connection.getResponseCode();
                    if (responseCode == 200) {
                        InputStream inputStream = connection.getInputStream();
                        String result = inputStream2String(inputStream);
                        LogUtil.d("请求数据成功：" + result);
                        if (result != null && callback != null) {
                            postSuccessObject(callback, new Gson().fromJson(result, cls));
                        }
                    } else {
                        if (callback != null) {
                            postFailed(callback, responseCode, new Exception("请求数据失败：" + responseCode));
                        }
                    }

                } catch (final Exception e) {
                    e.printStackTrace();
                    if (callback != null) {
                        postFailed(callback, 0, e);
                    }

                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }

    private static OutputStream getOutputStream(HttpURLConnection connection, Map<String, String> params) throws IOException {
        // 获取输出流,connection.getOutputStream已经包含了connect方法的调用
        OutputStream outputStream = connection.getOutputStream();
        StringBuilder sb = new StringBuilder();
        Set<Map.Entry<String, String>> sets = params.entrySet();
        // 将Hashmap转换为string
        for (Map.Entry<String, String> entry : sets) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        String param = sb.substring(0, sb.length() - 1);
        // 使用输出流将string类型的参数写到服务器
        outputStream.write(param.getBytes());
        outputStream.flush();
        return outputStream;
    }

    /**
     * 实例化对象
     */
    private static HttpURLConnection connect(String url) throws IOException {
        if (url.startsWith("https:")) {
            try {
                HttpsURLConnection httpsURLConnection;
                TrustManager[] var2 = new TrustManager[]{new MyTrustManager()};
                SSLContext var3 = SSLContext.getInstance("TLSv1");
                var3.init(null, var2, new SecureRandom());
                SSLSocketFactory var4 = var3.getSocketFactory();
                httpsURLConnection = (HttpsURLConnection) (new URL(url)).openConnection();
                httpsURLConnection.setSSLSocketFactory(var4);
                return httpsURLConnection;
            } catch (KeyManagementException var5) {
                var5.printStackTrace();
            } catch (NoSuchAlgorithmException var6) {
                var6.printStackTrace();
            } catch (Exception var7) {
                var7.printStackTrace();
            }
        }
        return (HttpURLConnection) new URL(url).openConnection();
    }


    private static void postSuccessString(final StringCallback callback, final String result) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onSuccess(result);
            }
        });
    }

    private static void postSuccessBitmap(final Callback callback, final Bitmap bitmap) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                BitmapCallback bitmapCallback = (BitmapCallback) callback;
                bitmapCallback.onSuccess(bitmap);
            }
        });
    }

    private static void postSuccessByte(final Callback callback, final byte[] bytes) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                ByteArrayCallback byteArrayCallback = (ByteArrayCallback) callback;
                byteArrayCallback.onSuccess(bytes);
            }
        });
    }

    private static <T> void postSuccessObject(final ObjectCallback<T> callback, final T t) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onSuccess(t);
            }
        });
    }

    private static void postSuccessFile(final Callback callback, final File file) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                FileCallback fileCallback = (FileCallback) callback;
                fileCallback.onComplete(file);
            }
        });
    }

    private static void postProgressFile(final Callback callback, final Progress progress) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                FileCallback fileCallback = (FileCallback) callback;
                fileCallback.onProcess(progress);
            }
        });
    }

    private static void postFailed(final Callback callback, final int code, final Exception e) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onFailure(code, e);
            }
        });
    }

    /**
     * 字节流转换成字符串
     *
     * @param inputStream 字节流
     */
    private static String inputStream2String(InputStream inputStream) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        int len;
        try {
            while ((len = inputStream.read(bytes)) != -1) {
                baos.write(bytes, 0, len);
            }
            return new String(baos.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 字节流转换成字节数组
     *
     * @param inputStream 输入流
     */
    private static byte[] inputStream2ByteArray(InputStream inputStream) {
        byte[] result = null;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        // 缓冲区
        byte[] bytes = new byte[1024];
        int len;
        try {
            // 使用字节数据输出流来保存数据
            while ((len = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, len);
            }
            result = outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public interface Callback {
        void onFailure(int code, Exception e);
    }

    public interface StringCallback extends Callback {
        void onSuccess(String result);
    }

    public interface BitmapCallback extends Callback {
        void onSuccess(Bitmap bitmap);
    }

    public interface ByteArrayCallback extends Callback {
        void onSuccess(byte[] bytes);
    }

    public interface ObjectCallback<T> extends Callback {
        void onSuccess(T t);
    }

    public interface FileCallback extends Callback {
        void onComplete(File file);

        void onProcess(Progress progress);
    }
}